#include "./models.hpp"

#include <assert.h>

#include "../utils/render_ref.h"

#include <chrono>

#include "../utils/create_image.h"

#include "./renderUtils.h"

namespace qbe::image2d {

double Models::default_factor = 1.1;

class ScreenshotHandler : public vsg::Inherit<vsg::Visitor, ScreenshotHandler> {
 public:
  bool do_image_capture = false;
  bool do_depth_capture = false;
  vsg::ref_ptr<vsg::Event> event;
  bool eventDebugTest = false;
  vsg::Path colorFilename;
  vsg::Path depthFilename;
  vsg::ref_ptr<vsg::Options> options;

  bool first = true;
  vsg::ref_ptr<vsg::Image> destinationImage;
  vsg::ref_ptr<vsg::DeviceMemory> deviceMemory;

  ScreenshotHandler(vsg::ref_ptr<vsg::Event> in_event, const vsg::Path& in_colorFilename, const vsg::Path& in_depthFilename,
                    vsg::ref_ptr<vsg::Options> in_options = {})
      : event(in_event), colorFilename(in_colorFilename), depthFilename(in_depthFilename), options(in_options) {}

  void screenshot_image(vsg::ref_ptr<vsg::Window> window, bool resize_ed, QImage& res) {
    // printInfo(window);

    do_image_capture = false;

    if (resize_ed) {
      // std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    if (eventDebugTest && event && event->status() == VK_EVENT_RESET) {
      // std::cout << "event->status() == VK_EVENT_RESET" << std::endl;
      // manually wait for the event to be signaled
      while (event->status() == VK_EVENT_RESET) {
        // std::cout << "w";
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
      }
      // std::cout << std::endl;
    }

    auto width = window->extent2D().width;
    auto height = window->extent2D().height;

    auto device = window->getDevice();
    auto physicalDevice = window->getPhysicalDevice();
    auto swapchain = window->getSwapchain();

    // get the colour buffer image of the previous rendered frame as the current frame hasn't been rendered yet.  The 1 in window->imageIndex(1) means image from 1 frame ago.
    auto sourceImage = window->imageView(window->imageIndex(0))->image;

    VkFormat sourceImageFormat = swapchain->getImageFormat();
    VkFormat targetImageFormat = sourceImageFormat;

    //
    // 1) Check to see if Blit is supported.
    //
    VkFormatProperties srcFormatProperties;
    vkGetPhysicalDeviceFormatProperties(*(physicalDevice), sourceImageFormat, &srcFormatProperties);

    VkFormatProperties destFormatProperties;
    vkGetPhysicalDeviceFormatProperties(*(physicalDevice), VK_FORMAT_R8G8B8A8_UNORM, &destFormatProperties);

    bool supportsBlit = ((srcFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) != 0) &&
                        ((destFormatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) != 0);

    if (supportsBlit) {
      // we can automatically convert the image format when blit, so take advantage of it to ensure RGBA
      targetImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
    }

    // vsg::info("supportsBlit = ", supportsBlit);

    //
    // 2) create image to write to
    //
    if (first || resize_ed) {
      destinationImage = vsg::Image::create();
      destinationImage->imageType = VK_IMAGE_TYPE_2D;
      destinationImage->format = targetImageFormat;
      destinationImage->extent.width = width;
      destinationImage->extent.height = height;
      destinationImage->extent.depth = 1;
      destinationImage->arrayLayers = 1;
      destinationImage->mipLevels = 1;
      destinationImage->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
      destinationImage->samples = VK_SAMPLE_COUNT_1_BIT;
      destinationImage->tiling = VK_IMAGE_TILING_LINEAR;
      destinationImage->usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;

      destinationImage->compile(device);

      deviceMemory = vsg::DeviceMemory::create(device, destinationImage->getMemoryRequirements(device->deviceID),
                                               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

      destinationImage->bind(deviceMemory, 0);
    }

    //
    // 3) create command buffer and submit to graphics queue
    //
    auto commands = vsg::Commands::create();

    if (event) {
      // vsg::info("Using vsg::Event/vkEvent");
      commands->addChild(vsg::WaitEvents::create(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, event));
      commands->addChild(vsg::ResetEvent::create(event, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT));
    }

    // 3.a) transition destinationImage to transfer destination initialLayout
    auto transitionDestinationImageToDestinationLayoutBarrier =
        vsg::ImageMemoryBarrier::create(0,                                                              // srcAccessMask
                                        VK_ACCESS_TRANSFER_WRITE_BIT,                                   // dstAccessMask
                                        VK_IMAGE_LAYOUT_UNDEFINED,                                      // oldLayout
                                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,                           // newLayout
                                        VK_QUEUE_FAMILY_IGNORED,                                        // srcQueueFamilyIndex
                                        VK_QUEUE_FAMILY_IGNORED,                                        // dstQueueFamilyIndex
                                        destinationImage,                                               // image
                                        VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}  // subresourceRange
        );

    // 3.b) transition swapChainImage from present to transfer source initialLayout
    auto transitionSourceImageToTransferSourceLayoutBarrier =
        vsg::ImageMemoryBarrier::create(VK_ACCESS_MEMORY_READ_BIT,                                      // srcAccessMask
                                        VK_ACCESS_TRANSFER_READ_BIT,                                    // dstAccessMask
                                        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,                                // oldLayout
                                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                           // newLayout
                                        VK_QUEUE_FAMILY_IGNORED,                                        // srcQueueFamilyIndex
                                        VK_QUEUE_FAMILY_IGNORED,                                        // dstQueueFamilyIndex
                                        sourceImage,                                                    // image
                                        VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}  // subresourceRange
        );

    auto cmd_transitionForTransferBarrier = vsg::PipelineBarrier::create(VK_PIPELINE_STAGE_TRANSFER_BIT,                        // srcStageMask
                                                                         VK_PIPELINE_STAGE_TRANSFER_BIT,                        // dstStageMask
                                                                         0,                                                     // dependencyFlags
                                                                         transitionDestinationImageToDestinationLayoutBarrier,  // barrier
                                                                         transitionSourceImageToTransferSourceLayoutBarrier     // barrier
    );

    commands->addChild(cmd_transitionForTransferBarrier);

    if (supportsBlit) {
      // 3.c.1) if blit using vkCmdBlitImage
      VkImageBlit region{};
      region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
      region.srcSubresource.layerCount = 1;
      region.srcOffsets[0] = VkOffset3D{0, 0, 0};
      region.srcOffsets[1] = VkOffset3D{static_cast<int32_t>(width), static_cast<int32_t>(height), 1};
      region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
      region.dstSubresource.layerCount = 1;
      region.dstOffsets[0] = VkOffset3D{0, 0, 0};
      region.dstOffsets[1] = VkOffset3D{static_cast<int32_t>(width), static_cast<int32_t>(height), 1};

      auto blitImage = vsg::BlitImage::create();
      blitImage->srcImage = sourceImage;
      blitImage->srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
      blitImage->dstImage = destinationImage;
      blitImage->dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
      blitImage->regions.push_back(region);
      blitImage->filter = VK_FILTER_NEAREST;

      commands->addChild(blitImage);
    } else {
      // 3.c.2) else use vkCmdCopyImage

      VkImageCopy region{};
      region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
      region.srcSubresource.layerCount = 1;
      region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
      region.dstSubresource.layerCount = 1;
      region.extent.width = width;
      region.extent.height = height;
      region.extent.depth = 1;

      auto copyImage = vsg::CopyImage::create();
      copyImage->srcImage = sourceImage;
      copyImage->srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
      copyImage->dstImage = destinationImage;
      copyImage->dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
      copyImage->regions.push_back(region);

      commands->addChild(copyImage);
    }

    // 3.d) transition destination image from transfer destination layout to general layout to enable mapping to image DeviceMemory
    auto transitionDestinationImageToMemoryReadBarrier =
        vsg::ImageMemoryBarrier::create(VK_ACCESS_TRANSFER_WRITE_BIT,                                   // srcAccessMask
                                        VK_ACCESS_MEMORY_READ_BIT,                                      // dstAccessMask
                                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,                           // oldLayout
                                        VK_IMAGE_LAYOUT_GENERAL,                                        // newLayout
                                        VK_QUEUE_FAMILY_IGNORED,                                        // srcQueueFamilyIndex
                                        VK_QUEUE_FAMILY_IGNORED,                                        // dstQueueFamilyIndex
                                        destinationImage,                                               // image
                                        VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}  // subresourceRange
        );

    // 3.e) transition swap chain image back to present
    auto transitionSourceImageBackToPresentBarrier =
        vsg::ImageMemoryBarrier::create(VK_ACCESS_TRANSFER_READ_BIT,                                    // srcAccessMask
                                        VK_ACCESS_MEMORY_READ_BIT,                                      // dstAccessMask
                                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                           // oldLayout
                                        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,                                // newLayout
                                        VK_QUEUE_FAMILY_IGNORED,                                        // srcQueueFamilyIndex
                                        VK_QUEUE_FAMILY_IGNORED,                                        // dstQueueFamilyIndex
                                        sourceImage,                                                    // image
                                        VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}  // subresourceRange
        );

    auto cmd_transitionFromTransferBarrier = vsg::PipelineBarrier::create(VK_PIPELINE_STAGE_TRANSFER_BIT,                 // srcStageMask
                                                                          VK_PIPELINE_STAGE_TRANSFER_BIT,                 // dstStageMask
                                                                          0,                                              // dependencyFlags
                                                                          transitionDestinationImageToMemoryReadBarrier,  // barrier
                                                                          transitionSourceImageBackToPresentBarrier       // barrier
    );

    commands->addChild(cmd_transitionFromTransferBarrier);

    auto fence = vsg::Fence::create(device);
    auto queueFamilyIndex = physicalDevice->getQueueFamily(VK_QUEUE_GRAPHICS_BIT);
    auto commandPool = vsg::CommandPool::create(device, queueFamilyIndex);
    auto queue = device->getQueue(queueFamilyIndex);

    vsg::submitCommandsToQueue(commandPool, fence, 100000000000, queue, [&](vsg::CommandBuffer& commandBuffer) { commands->record(commandBuffer); });

    //
    // 4) map image and copy
    //
    VkImageSubresource subResource{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0};
    VkSubresourceLayout subResourceLayout;
    vkGetImageSubresourceLayout(*device, destinationImage->vk(device->deviceID), &subResource, &subResourceLayout);

    size_t destRowWidth = width * sizeof(vsg::ubvec4);
    vsg::ref_ptr<vsg::Data> imageData;
    if (destRowWidth == subResourceLayout.rowPitch) {
      imageData = vsg::MappedData<vsg::ubvec4Array2D>::create(deviceMemory, subResourceLayout.offset, 0, vsg::Data::Properties{targetImageFormat},
                                                              width, height);  // deviceMemory, offset, flags and dimensions
    } else {
      // Map the buffer memory and assign as a ubyteArray that will automatically unmap itself on destruction.
      // A ubyteArray is used as the graphics buffer memory is not contiguous like vsg::Array2D, so map to a flat buffer first then copy to Array2D.
      auto mappedData = vsg::MappedData<vsg::ubyteArray>::create(deviceMemory, subResourceLayout.offset, 0, vsg::Data::Properties{targetImageFormat},
                                                                 subResourceLayout.rowPitch * height);
      imageData = vsg::ubvec4Array2D::create(width, height, vsg::Data::Properties{targetImageFormat});
      for (uint32_t row = 0; row < height; ++row) {
        std::memcpy(imageData->dataPointer(row * width), mappedData->dataPointer(row * subResourceLayout.rowPitch), destRowWidth);
      }
    }

    vsgXchange::all obj;
    static auto co = qbe::utils::TempRender::CreateImage();
    res = co.vsgDataToQImage(imageData);

    // obj.write(imageData, colorFilename, options);

    first = false;

    // if (obj.write(imageData, colorFilename, options)) {
    //   static auto co = qbe::utils::TempRender::CreateImage();
    //   res = co.vsgDataToQImage(imageData);
    //   // std::cout << "Written color buffer to " << colorFilename << std::endl;
    // } else {
    //   assert(0);
    //   // std::cout << "Failed to write color buffer to " << colorFilename << std::endl;
    // }
  }
};

void Models::init() {
  options = vsg::Options::create();

  options->paths = {
      // "D:/bylz/projects/qlayout-test/data",
      // "E:/users/xqf/qlayout-test/data",
      // "E:/projects/cpp/qlayout-test/data",
      // "E:/Project/vs_code/qlayout-test/data",
      // "C:/Users/xqf/Desktop/project/qlayout-test/data",
      // "C:/Users/dg/qlayout-test/data",
      "../../../data",
      "./data",
  };

  options->fileCache = vsg::getEnv("VSG_FILE_CACHE");
  // options->paths = vsg::getEnvPaths("VSG_FILE_PATH");

  windowTraits->windowTitle = "Image2d window";
  windowTraits->width = 500;
  windowTraits->height = 400;

  windowTraits->swapchainPreferences.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  windowTraits->depthImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;

  int argc = 0;
  char** argv = nullptr;

  vsg::CommandLine arguments(&argc, argv);
  arguments.read(options);
  windowTraits->debugLayer = arguments.read({"--debug", "-d"});
  windowTraits->apiDumpLayer = arguments.read({"--api", "-a"});
  arguments.read("--screen", windowTraits->screenNum);
  arguments.read("--display", windowTraits->display);
  arguments.read("--samples", windowTraits->samples);

  use_vkEvent = arguments.read("--use-vkEvent");
  numFrames = arguments.value(-1, "-f");

  if (windowTraits->samples != VK_SAMPLE_COUNT_1_BIT)
    windowTraits->vulkanVersion = VK_API_VERSION_1_2;

  uint32_t vk_major = 1, vk_minor = 0;
  if (std::string vk_version; arguments.read("--vulkan", vk_version)) {
    char c;
    std::stringstream vk_version_str(vk_version);
    vk_version_str >> vk_major >> c >> vk_minor;
    // std::cout << "vk_major = " << vk_major << std::endl;
    // std::cout << "vk_minor = " << vk_minor << std::endl;
  }

  if (arguments.errors())
    assert(0);

  vsg_scene = vsg::Group::create();

  QWindow* parent = nullptr;
  // viewer = query.get_resource<vsg::ref_ptr<vsgQt::Viewer>>();
  viewer = vsgQt::Viewer::create();
  window = new vsgQt::Window(viewer, windowTraits, parent);

  window->setTitle("2D Image");
  window->initializeWindow();

  // window->show();
  // window->hide();

  if (!windowTraits->device) {
    windowTraits->device = window->windowAdapter->getOrCreateDevice();
  }

  windowTraits->deviceExtensionNames = {VK_KHR_MULTIVIEW_EXTENSION_NAME, VK_KHR_MAINTENANCE2_EXTENSION_NAME,
                                        VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME};

  device = windowTraits->device;

  if (!window) {
    assert(0);
  }

  depthStencilResolve_properites =
      device->getPhysicalDevice()
          ->getProperties<VkPhysicalDeviceDepthStencilResolveProperties, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES>();

  {
    event = vsg::Event::create_if(use_vkEvent, device);  // Vulkan creates VkEvent in an unsignalled state

    static vsg::ref_ptr<ScreenshotHandler> screenshotHandler_t = ScreenshotHandler::create(event, "Test.png", "DepthFile.vsgt", options);
    screenshotHandler = screenshotHandler_t;
    viewer->addEventHandler(screenshotHandler_t);

    camera = vsg::Camera::create();

    commandGraph = vsg::createCommandGraphForView(window->windowAdapter, camera, vsg_scene);
    if (event)
      commandGraph->addChild(vsg::SetEvent::create(event, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT));

    auto secondary_view = vsg::View::create(camera, vsg_scene);
    secondary_RenderGraph = vsg::RenderGraph::create(window->windowAdapter, secondary_view);
    secondary_RenderGraph->clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
    commandGraph->addChild(secondary_RenderGraph);

    viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});
  }

  {
    viewport = vsg::ViewportState::create(0, 0, windowTraits->width, windowTraits->height);
    width_half = static_cast<double>(windowTraits->width / 2);
    height_half = static_cast<double>(windowTraits->height / 2);
  }

  windowTraits->deviceExtensionNames.clear();
  windowTraits->swapchainPreferences.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  windowTraits->depthImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}

Models::Models(vsg::ref_ptr<vsg::WindowTraits> traits) : windowTraits(traits) {
  query = nullptr;

  vsgXchange::init();

  instance = this;

  query = nullptr;

  init();
}

Models::Models(ecs::Query* _query) : query(_query) {
  vsgXchange::init();

  instance = this;

  windowTraits = query->get_resource<vsg::ref_ptr<vsg::WindowTraits>>();

  init();
}

static bool use_square = true;

QImage Models::saveImage2d(vsg::ref_ptr<vsg::Node> node, std::string fileName, double disFactor) {
  QImage res;

  vsg_scene->children.clear();
  vsg_scene->addChild(node);

  {
    vsg::ComputeBounds computeBounds;
    vsg_scene->accept(computeBounds);
    computeBounds.bounds.min.z = 0;
    computeBounds.bounds.max.z = 0;

    vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5;
    double radius = vsg::length(computeBounds.bounds.max - computeBounds.bounds.min) * 0.6;

    double width = (computeBounds.bounds.max.x - computeBounds.bounds.min.x);
    double height = (computeBounds.bounds.max.y - computeBounds.bounds.min.y);

    double use_width = width / 2.0 * disFactor;
    double use_height = height / 2.0 * disFactor;

    if (use_square) {
      use_width = std::max(use_width, use_height);
      use_height = use_width;
    }
    if (!resize_ed) {
      use_square = true;
    }

    // 创建正交相机
    auto ortho = vsg::Orthographic::create(-use_width, use_width, -use_height, use_height, 0.0, radius * 4.5);
    auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(0, 0, -1), centre, vsg::dvec3(0, 1, 0));
    auto ct = vsg::Camera::create(ortho, lookAt, viewport);

    *camera = *ct;
  }

  viewer->pollEvents(false);
  viewer->handleEvents();
  viewer->compile();

  int count = 1;

  // rendering main loop
  while (viewer->advanceToNextFrame()) {
    // pass any events into EventHandlers assigned to the Viewer
    viewer->handleEvents();

    viewer->update();

    viewer->recordAndSubmit();

    viewer->present();

    if (count == 0) {
      screenshotHandler->screenshot_image(window->windowAdapter, resize_ed, res);
      return res;
    }

    count--;
  }

  return res;
}

QImage Models::saveImage2d(qlib::Reference::s_ptr refer, std::string fileName, double disFactor, bool useQuery) {

  if (useQuery) {
    if (query) {
      auto& reg = query->get_resource<qlib::Cell::s_ptr>()->reg;
      qbe::utils::TempRender::RenderRef ref = qbe::utils::TempRender::RenderRef(refer, reg, *query, 0);
      ref.updateTransform();

      auto switchNode = ref.switchObject;
      return saveImage2d(switchNode, fileName, disFactor);
    } else {
      qbe::utils::TempRender::RenderRef ref = qbe::utils::TempRender::RenderRef(refer, 0, options);
      ref.updateTransform();

      auto switchNode = ref.switchObject;
      return saveImage2d(switchNode, fileName, disFactor);
    }

  } else {
    auto cell = refer->cell;
    auto& reg = cell->reg;
    auto view = reg.view<qlib::Rectangle::s_ptr>();

    qlib::Rectangle::s_ptr rectangle;
    view.each([&rectangle](entt::entity e, qlib::Rectangle::s_ptr r) { rectangle = r; });

    auto refer_t = qlib::Reference::create();
    auto cell_new = qlib::Cell::create();
    refer_t->cell = cell_new;

    auto points = rectangle->to_polygon()->points;
    auto path = qlib::Path::create();
    path->layer = rectangle->layer;
    path->spine.points = points;
    path->spine.points.push_back(points[0]);
    cell_new->spawn(path);

    qbe::utils::TempRender::RenderRef ref = qbe::utils::TempRender::RenderRef(refer_t, 0, options, funvc);
    ref.updateTransform();

    auto switchNode = ref.switchObject;

    auto node = qbe::getLayerNode(funvc, rectangle->layer, rectangle);

    auto node_total = vsg::Group::create();
    node_total->addChild(node);
    node_total->addChild(switchNode);

    return saveImage2d(node_total, fileName, disFactor);
  }
}

void Models::resize(int width, int height) {
  if (width == width_real && height == height_real)
    return;

  window->resize(width, height);

  viewport = vsg::ViewportState::create(0, 0, width, height);
  width_real = width;
  height_real = height;

  resize_ed = true;
}

uint32_t Models::count = 0;

QImage Models::saveImage2d(qlib::Reference::s_ptr refer, int width, int height, bool clear_color, double disFactor, bool useQuery) {
  // 获取开始时间点
  auto start = std::chrono::high_resolution_clock::now();

  // 调用需要测量的函数
  QImage image;
  {
    if (clear_color) {
      setBackColor(vsg::vec4(0.0, 0.0, 0.0, 1.0));
    }

    resize(width, height);

    std::string fileName = "./Image2d_Use.png";

    image = saveImage2d(refer, fileName, disFactor, useQuery);

    if (resize_ed) {
      resize_ed = false;
      image = saveImage2d(refer, fileName, disFactor, useQuery);
    }
  }

  // 获取结束时间点
  auto end = std::chrono::high_resolution_clock::now();

  // 计算持续时间
  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

  // 打印执行时间（秒）
  // std::cout << "Image 2d index-" << std::to_string(count) << " time-" << duration.count() << " milliseconds" << std::endl;

  count++;
  return image;
}

Models* Models::Instance() {
  return instance;
}

void Models::setInstance(Models* instance_t) {
  instance = instance_t;
}

Models* Models::instance = nullptr;

QImage Models::saveImage2d(uint32_t layer, int width, int height, double disFactor) {
  return QImage();
}

QImage Models::saveImage2d(std::function<std::vector<std::string>(uint32_t)>& _funvc, uint32_t layer, int width, int height, double disFactor) {
  funvc = _funvc;

  disFactor = 1.1;
  use_square = false;

  qlib::Cell::s_ptr cell = qlib::Cell::create();
  qlib::Reference::s_ptr refer = qlib::Reference::create();

  refer->cell = cell;

  auto& reg = cell->reg;

  qlib::Rectangle::s_ptr rect = qlib::Rectangle::create();
  rect->pos = qlib::Vec2d(0, 0);
  rect->width = width;
  rect->height = height;
  rect->layer = layer;

  auto e = reg.create();
  reg.emplace<qlib::Rectangle::s_ptr>(e, rect);

  setBackColor(vsg::vec4(1.0, 1.0, 1.0, 1.0));

  return saveImage2d(refer, width, height, false, disFactor, false);
}

void Models::setBackColor(vsg::vec4 color) {
  secondary_RenderGraph->clearValues[0].color = {{color.r, color.g, color.b, color.a}};
}

void Models::setQuery(ecs::Query* _query) {
  query = _query;
}

}  // namespace qbe::image2d